﻿using System;
using System.ServiceModel;
using System.ServiceModel.Channels;

namespace RG.Common
{
    /// <summary>
    /// Класс-обертка по мотивам http://blogs.gotdotnet.ru/personal/bezzus/PermaLink.aspx?guid=c4ca892a-1e0b-453c-9aec-166534964075
    /// Удобнее стандартного тем, что можно использовать один и тот же интерфейс для контрактов и на клиенте и на сервере
    /// плюс относительно корректно работает с каналом (закрывает при ошибке и т.д.)
    /// </summary>
    /// <typeparam name="TChannel"></typeparam>
    public class FactoryWrapperBase<TChannel> where TChannel : class
    {
        protected static ChannelFactory<TChannel> _factory;
        // ну, или любой другой набор параметров, который вам нужен
        // для корректного создания фабрики...
        //

        public FactoryWrapperBase()
        {
            _factory = new ChannelFactory<TChannel>();
        }

        public FactoryWrapperBase(string endpointConfigurationName)
        {
            _factory = new ChannelFactory<TChannel>(endpointConfigurationName);
        }

        public FactoryWrapperBase(Binding binding, EndpointAddress endpoint)
        {
            _factory = new ChannelFactory<TChannel>(binding, endpoint);
        }

        public TResult Execute<TResult>(Func<TChannel, TResult> action)
        {
            return Execute(action, null);
        }

        public TResult Execute<TResult>(Func<TChannel, TResult> action, AddressHeader addressHeader)
        {
            var proxy = default(TChannel);

            TResult result;
            try
            {
                PrepareFactory(addressHeader);
                proxy = _factory.CreateChannel();
                ((IClientChannel)proxy).Open();
                result = action(proxy);
                ((IClientChannel)proxy).Close();
            }
            catch (Exception)
            {
                if (proxy != null)
                    ((IClientChannel)proxy).Abort();
                throw;
            }
            return result;
        }

        public void Execute(Action <TChannel> action)
        {
            var proxy = default(TChannel);

            try
            {
                PrepareFactory(null);
                proxy = _factory.CreateChannel();
                ((IClientChannel)proxy).Open();
                action(proxy);
                ((IClientChannel)proxy).Close();
            }
            catch (Exception)
            {
                if (proxy != null)
                    ((IClientChannel)proxy).Abort();
                throw;
            }
        }

        public Action<EndpointAddressBuilder> OnSpecificHeaders { get; set; }

        private void PrepareFactory(AddressHeader addressHeader)
        {
            var builder = new EndpointAddressBuilder(_factory.Endpoint.Address);

#if Release
            const string version = "Release"; 
#elif Beta
            const string version = "BETA";
#else
            const string version = "DEBUG";
#endif
            builder.Headers.Clear();
            if (OnSpecificHeaders != null)
                OnSpecificHeaders(builder);
            //builder.AddMariaHeader("Version", version);
            if (addressHeader != null)
                builder.Headers.Add(addressHeader);

            _factory.Endpoint.Address = builder.ToEndpointAddress();
        }

    }
}